package com.future.mashibing.class02;

public class Code02_Bit {
    public static void main(String[] args) {
        int a, b;
        int sumTimes = 100000;
        System.out.println("开始测试");
        while (sumTimes-- > 1) {
            a = (int) (Math.random() * 10);
            b = (int) (Math.random() * 20);
           /* if ((a + b) != bitAdd(a, b)) {
                System.out.println(a + "+" + b + "=" + bitAdd(a, b));
                throw new RuntimeException("位运算加法出现问题了！！");
            }
            if ((a - b) != bitMinus(a, b)) {
                throw new RuntimeException("位运算减法出现问题了！！");
            }*/
            if ((a * b) != bitMulti(a, b)) {
                throw new RuntimeException("位运算乘法出现问题了！！");
            }
        }
        System.out.println("结束测试");
        System.out.println("开始测试取反");
        a = 10;
        System.out.println(String.format("%s的取反（~%s）等于%s", a, a, ~a));
        System.out.println("结束测试取反");
    }

    /**
     * 两数相加（最好的方式，没有出现“+”号）
     *
     * @param a
     * @param b
     * @return
     */
    private static int bitAdd(int a, int b) {
        // 不能为sum=0,否则当b=0,但a不等于0时，返回sum=0
        int sum = a;
        while (b != 0) {
            sum = a ^ b;
            b = (a & b) << 1;
            a = sum;
        }
        return sum;
    }

    /**
     * 两数相减
     * 相当于a+(-b):a加上b的相反数
     *
     * @param a
     * @param b
     * @return
     */
    private static int bitMinus(int a, int b) {
        return bitAdd(a, negNum(b));
    }

    /**
     * 两数相乘
     * 4*6 <==>00000100*00000110
     * 00000100
     * * 00000110
     * -----------
     * 00001000
     * +0000010000
     * -------------
     * 0000011000
     * =>16+8=24
     *
     * @param a
     * @param b
     * @return
     */
    private static int bitMulti(int a, int b) {
        int res = 0;
        while (b != 0) {
            if ((b & 1) != 0) {
                res = bitAdd(res, a);
            }
            a <<= 1;
            b >>>= 1;
        }
        return res;
    }

    /**
     * 两数相除，不能直接计算Integer.MIN_VALUE,
     * 因为这里涉及取绝对值
     * 24/4 = 6 <==>
     *  00000100*00000110
     *  00000100*00000100 + 00000100*00000010
     *  00010000+00001000
     *  =16+8=24
     *
     *  注意：向下取整 18/7 《=》14/7 = 2
     * @param a
     * @param b
     * @return
     */
    public static int biDiv(int a, int b) {
        // 如果是负数，转成相反数
        int x = isNeg(a) ? negNum(a) : a;
        int y = isNeg(b) ? negNum(b) : b;
        int res = 0;
        // x/y
        // 非负数，所以不需要从31位开始
        for (int i = 30; i >=0 ; i--) {
            if ((x >> i) >= y){
                res |= (1<<i);
                x = bitMinus(x,y<<i);
            }
        }
        // 正正|负负得正，正负|负正得负
        return isNeg(a) ^ isNeg(b) ? negNum(res) :res;
    }

    /**
     * 位运算除法统一入口
     *
     * @param a
     * @param b
     * @return
     */
    public static int divide(int a, int b) {
        if (a == Integer.MIN_VALUE && b == Integer.MIN_VALUE) {
            return 1;
        } else if (b == Integer.MIN_VALUE) {
            return 0;
        } else if (a == Integer.MIN_VALUE) {
            if (b == negNum(1)) {
                return Integer.MAX_VALUE;
            } else {
                /**
                 * example: 假设范围-15~14
                 * 计算 -15/3?
                 * 由于|-15|越界了，明显不行
                 * 思路：(-15+1)/3 = -4
                 * -15-(3*(-4)) = -3
                 * -3/3 = -1
                 * 结果：-4+（-1）=-5
                 */
                int c = biDiv(bitAdd(a, 1), b);
                return bitAdd(c, biDiv(bitMinus(a, bitMulti(c, b)), b));
            }
        } else {
            return biDiv(a, b);
        }
    }
    /**
     * 是否是正数
     * @param n
     * @return
     */
    public static boolean isNeg(int n){
        return n < 0;
    }

    /**
     * 求a的相反数
     * <p>
     * ~9 = -10
     * ~10 = -11
     *
     * @param a
     * @return
     */
    private static int negNum(int a) {
        return bitAdd(~a, 1);
    }

}

